;   This program is free software: you can redistribute it and/or modify
;   it under the terms of the GNU General Public License as published by
;   the Free Software Foundation, either version 3 of the License, or
;   (at your option) any later version.
;
;   This program is distributed in the hope that it will be useful,
;   but WITHOUT ANY WARRANTY; without even the implied warranty of
;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;   GNU General Public License for more details.
;
;   You should have received a copy of the GNU General Public License
;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
;
;程序名称:Y-ABCDE.ASM
;功能:根据公式,计算Y值
;环境:16BIT DOS实模式(windows/dos或dosbox)
;编译器:MASM 5.1-6X 
;用法:看说明
;返回值:没有
;破坏寄存器:不适用
;
;应sjydhqhome的遨请,为这烂题目写了一个汇编,正想贴出却发现原贴被删了,好样的!
;没有原题目,大概就是读取五个数ABCDE,根据公式:
;(Y=AxB+C/D-E),把正负结果分别存入BUF1和BUF2...
;
;草草写的这一个,少于300行..
;为了加点趣味和亲和性,所以加了运算元的显示,若不要这些,大概150行就可以了
;程式只读入两个数字,接受负数,输入到D值时,若发现为0,不会接受并清除
;输入时,程式会显示和指出运算过程,光是这些烂功能就花掉百多行代码..
;结果直接印在后面,这样直观一些..
;按ESC或ENTER离开
;时间有限,加了小量解释,没空侦错,若有bug请报告..

;--------------------------------------
;http://pan.baidu.com/s/1kT7rtiB
;
 max_y equ 20 ;最大列数
 buf_pos equ 31 ;buf 行位置
 first_row_pos equ 3 ;第一Y列行数
;
data segment
 title1 label byte
 db '---- << Equation >>------------ << Result >> -',0dh,0ah
 db 'Y = A x B + C / D - E',10 dup (20h),'BUF1(+) BUF2(-)$'
 title2 db 22 dup (20h),'$'
 Step_pos db 04,08,12,16,20 ;步骤位置
 value_buf dw 5 dup (0)
 y_num_str db 'Y00=($' ;列编号字串
 operator_str db 'x',0,')+(',0,'/',0,')-(',0,')',0  ;运算符
 operator_pos dw 0 ;;步骤计数
 y_num dw 0  ;列编号
 BUF1 DW max_y DUP (0)  ;结果缓冲
 BUF_len equ $ - offset BUF1
 BUF2 DW max_y DUP (0)
 buf_str db 6 dup (20h),'$'
 sign db 0  ;负号
 operator_off dw 0
data ends

code segment
assume ds:data,cs:code
start:
 mov ax,data
 mov ds,ax
 mov es,ax
 call cls
 mov dx,offset title1
 mov ah,9
 int 21h
next0:
 mov operator_pos,0 ;init
 mov si,offset y_num_str
 mov ax,y_num
 add al,1
 aam
 or ax,3030h
 xchg ah,al
 cmp al,'0'
 jnz next0a
 mov al,20h
 xchg ah,al
next0a:
 mov [si+1],ax    ;以上计算列号
 mov dx,y_num
 mov dh,dl
 add dh,first_row_pos
 mov dl,0
 call setpos
 mov dx,si
 mov ah,9
 int 21h  ;print input
 mov di,offset value_buf
 mov ax,offset operator_str 
 mov operator_off,ax
next1:
 call print_pos ;列印运算到哪一位置
 call get_input ;读输入
 jnc next1a
 jmp quit  ;exit to dos,may be keyin esc or enter
next1a:
 mov si,operator_off 
next1b:
 lodsb
 or al,al
 jz next2
 int 29h  ;列出当前运算元
 jmp short next1b
next2:
 mov operator_off,si
 inc operator_pos
 cmp operator_pos,5 ;是否已输入五个数
 jb next1 ;未够
 mov di,10000  ;start calc, ;Y = A x B + C / D - E ;开始计算结果
 mov si,offset value_buf
 mov ax,[si] ;get A  ;取 A
 mov bx,[si+2] ;Get B ;取 B
 imul bx  ; A x B
 test ax,8000h ;test neg ;是否负数
 jz next3 ;不是
 neg ax  ;取补
 sub di,ax  ;大数10000减 A x B
 jmp short next3a
next3:
 add di,ax ;大数10000 +  A x B
next3a:
 mov ax,[si+4] ;get C ;取C
 mov bx,[si+6] ;get D ;must not 0 /取 D,之前已检测不为0
 xor dx,dx
 xor cx,cx
 test ax,8000h
 jz next3b
 xor cx,1
 neg ax
next3b:
 test bx,8000h
 jz next3c
 xor cx,1
 neg bx
next3c:
 div bx ; C / D
 test cx,1h ;test neg
 jz next6
 sub di,ax
 jmp short next6a
next6:
 add di,ax
 next6a:
 mov ax,[si+8] ; get E
 test ax,8000h ;test neg
 jz next7
 neg ax
 add di,ax
 jmp short next7a
next7:
 sub di,ax   ;get result 结果在DI
next7a:
 sub di,10000  ;ajust ;调整
 mov dx,di
 mov bx,di
 xor bp,bp
 mov di,offset buf_str
 mov si,y_num ;取列号
 shl si,1
 add si,offset BUF1
 mov cx,BUF_len
 test bx,8000h ;是否负
 jz next8 ;不是
 mov al,'-'  ;若负加[-]号
 stosb ;存
 neg dx      ; neg result最正数值印出
 mov bp,8 ; neg len
 add si,cx
next8:
 mov [si],bx  ;store result ;存
 mov ax,dx
 call print_ax ;存结果
 mov dx,buf_pos
 add dx,bp
 mov ax,y_num ;根据列号,计算位置
 mov dh,al
 add dh,first_row_pos
 call setpos ;设光标
 mov dx,offset buf_str  ;印结果
 mov ah,9
 int 21h
 inc y_num ;增加列数
 cmp y_num,max_y ;是否限制值
 jae quit ;已到
 jmp next0 ;下一列输入
quit:
 mov ah,4ch
 int 21h
;----------------------
get_input:
 mov bp,2
 mov bx,0
 mov cl,8
 mov sign,0
reinput:
 mov ah,7
 int 21h
 cmp al,1bh ;esc
 jnz get7
get6:
 stc  ;enter 和  ESC离开
 ret
get7:
 cmp al,0dh ;enter
 jz get6
 cmp al,'-'
 jnz get10
 cmp sign,1 ;减号设定标记
 jz reinput
 cmp bp,2
 jnz get10
 mov sign,1  
 int 29h   ;印出 [-]
 jmp short reinput
get10:
 cmp al,'0'
 jb reinput
 cmp al,'9'
 ja reinput  ;不是0-9,再输入
 int 29h
 sub al,'0'
 shl bx,cl ;若bx=0001,变 0100
 or bl,al
 dec bp
 jnz reinput
get20:
 mov ax,bx ; bx=BCD 
 aad   ;bcd除法前调整,若ax =0101, aad后,ax= 000B
 or ax,ax  ;check 0
 jnz get30 ;不是0
 cmp operator_pos,3  ;IF D,no 0 allow,若是0,是否D值,若是,则不接受
 jnz get30
 mov cx,2
 call backspace ;清除输入
 jmp short get_input
get30:
 cmp sign,0
 jz get40
 neg ax
get40:
 stosw
 clc
 ret
;----------------------
print_pos: ;以下根据列号印出 [^]
 call getpos
 push dx
 call print_arrow
 mov ax,operator_pos 
 mov bx,offset Step_pos
 xlatb
 mov dl,al
 mov dh,first_row_pos - 1
 call setpos
 mov al,'^'
 int 29h
 pop dx
 call setpos
 ret
;----------------------
print_arrow: ;印出 [^]
 mov dh,first_row_pos - 1
 mov dl,0
 call setpos
 mov dx,offset title2 ;clear
 mov ah,9
 int 21h
;----------------------
getpos:  ;读光标位置
 mov bh,0
 mov ah,3
 int 10h
 ret
;----------------------
setpos: ;设定光标位置
 mov bh,0
 mov ah,2
 int 10h
 ret
;----------------------
backspace: ;backspace模拟
 mov dl,8
 mov ah,2
 int 21h
 mov dl,20h
 int 21h
 mov dl,8
 int 21h
 loop backspace
 ret
;----------------------
print_AX:  ;印出AX值子程序
 mov cx,0 ;清0
 mov bx,10 ;除法准备
Pax1:
 mov dx,0 ;清0
 div bx ;ax /10 ,若1234 ,除10后,dl得余数4,
 push dx ;保存, ax=1234,依次保存4,3,2,1
 inc cx ;累加个数
 or ax,ax ;是否已除尽
 jnz Pax1 ;不是,再除
 mov bl,cl ;存个数
Pax2:
 pop ax  ;后入先出,先印出第一数,然后第二....
 or al,30h ;转ascii
 stosb ;存入字串缓冲
 loop Pax2 ;下一个
 mov cl,bl ;取回个数
 sub cx,5 
 neg cx  ;剩余数
 mov al,20h 
 rep stosb ;补空白
 ret
;----------------------
cls: ;清屏
 mov ah,0fh                  ;get display mode to al
 int 10h
 mov ah,0                    ;Set display mode
 int 10h
 ret
;----------------------
 code ends
 end start